package tron.tools;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.Data;

import java.sql.Timestamp;
import java.time.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * @author Tron
 * @create 2019-12-03
 */
public class TronTool {

    /**
     * api  startTime endTime
     */

    private static final ThreadLocal<Map<String, Map<String, Instant>>> time = new ThreadLocal<>();

    public static void apiTime(String apiName) {
        // 线程变量为空时先初始化
        if (null == time.get()) {
            final HashMap<String, Map<String, Instant>> initMap = new LinkedHashMap<>();
            time.set(initMap);
        }
        // 没有记录过添加startTime 记录过添加endTime
        final Map<String, Map<String, Instant>> apiTimeMap = time.get();
        if (apiTimeMap.containsKey(apiName)) {
            final Map<String, Instant> instantMap = apiTimeMap.get(apiName);
            instantMap.put("endTime", Instant.now());
        } else {
            final LinkedHashMap<String, Instant> instantMap = new LinkedHashMap<>();
            instantMap.put("startTime", Instant.now());
            apiTimeMap.put(apiName, instantMap);
        }
        time.set(apiTimeMap);
    }

    public static StringBuilder getTime() {
        final Map<String, Map<String, Instant>> apiTimeMap = time.get();
        final StringBuilder stringBuilder = new StringBuilder();
        int no = 0;
        // 整合调用步骤
        final Set<Map.Entry<String, Map<String, Instant>>> entries = apiTimeMap.entrySet();
        for (Map.Entry<String, Map<String, Instant>> entry : entries) {
            final String key = entry.getKey();
            final Map<String, Instant> value = entry.getValue();
            // k api名称 v 起始时间和结束时间
            final long useTime = Duration.between(value.get("startTime"), value.get("endTime")).toMillis();
            stringBuilder.append("(").append(no++).append(") ").append(" [ ").append(key).append(" ] ").append(" 调用时间：").append(useTime);
            // 耗时超过一秒的方法加星标
            if (useTime > 1000) {
                stringBuilder.append(" ★★★★★★ ");
            }
            stringBuilder.append("\n");
        }
        return stringBuilder;
    }

    public static void cleanTime() {
        time.remove();
    }


    /**
     * -----------------------------------------时间-----------------------------------------
     */

    /**
     * 国际UTC, Universal Time Coordinated 与 格林尼治平均时(GMT, Greenwich Mean Time)一样
     * 北京时区是东八区，领先UTC八个小时
     * @param localDateTime
     * @return
     */

    /**
     * localDateTime 转 Date
     *
     * @param localDateTime
     * @return Date
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.toInstant(ZoneOffset.ofHours(8)));
    }

    /**
     * Date 转 LocalDateTime
     *
     * @param date
     * @return LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /**
     * Date 转 Timestamp
     *
     * @param date
     * @return Timestamp
     */
    private static Timestamp toTimestamp(Date date) {
        return dateOrLocalDateTimeToTimeStamp(date);
    }

    /**
     * LocalDateTime 转 Timestamp
     *
     * @param localDateTime
     * @return Timestamp
     */
    private static Timestamp toTimestamp(LocalDateTime localDateTime) {
        return dateOrLocalDateTimeToTimeStamp(localDateTime);
    }

    /**
     * 数据存储时间转换
     *
     * @param o
     * @return Timestamp
     */
    public static Timestamp dateOrLocalDateTimeToTimeStamp(Object o) {
        if (o instanceof Date) {
            Date date = (Date) o;
            return Timestamp.from(date.toInstant());
        } else {
            LocalDateTime localDateTime = (LocalDateTime) o;
            return Timestamp.valueOf(localDateTime);
        }
    }



    /**
     * 判断字符串有非空字符内容
     *
     * @param str
     * @return Boolean
     */
    private static boolean hasLength(CharSequence str) {
        return (str != null && str.length() > 0);
    }






    /**
     * 取出指定位置的内容，如：<a>取出这里的内容</a>，可以匹配多个。
     *
     * @param startWith
     * @param endWith
     * @param str
     * @return
     */
    public static List<String> matchString(String str, String startWith, String endWith) {
        ArrayList<String> strings = new ArrayList<>();
        if (!hasLength(str) || !hasLength(startWith) || !hasLength(endWith)) {
            return strings;
        }
        Matcher matcher = Pattern.compile("(?<=" + startWith + ").*?(?=" + endWith + ")").matcher(str);
        while (matcher.find()) {
            strings.add(matcher.group());
        }
        return strings;
    }


    /**
     * 获取分组数据包装集合
     */
    public static <T> ArrayList<GroupData> getGroupData(List<T> list, Function<T, String> function) {
        Map<String, List<T>> collect = list.stream().collect(groupingBy(function));
        ArrayList<GroupData> groupDataList = new ArrayList<>();
        collect.forEach((k, v) -> {
            GroupData groupData = new GroupData();
            groupData.setGroupName(k);
            groupData.setGroupItems(v);
            groupDataList.add(groupData);
        });
        return groupDataList;
    }

    @Data
    public static class GroupData {
        private String groupName;
        private List groupItems;
    }

    /**
     * map集合去重
     *
     * @param list
     * @param key
     * @return
     */
    public static List<Map<String, Object>> distinct(List<Map<String, Object>> list, String key) {
        List<Map<String, Object>> collect = list.stream().filter(distinctByKey(e -> e.get(key))).collect(Collectors.toList());
        return collect;
    }

    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 正则替换所有特殊字符
     *
     * @param orgStr
     * @return
     */
    public static String replaceSpecStr(String orgStr) {
        if (null != orgStr && !"".equals(orgStr.trim())) {
            String regEx = "[\\s~·`!！@#￥$%^……&*（()）\\-——\\-_=+【\\[\\]】｛{}｝\\|、\\\\；;：:‘'“”\"，,《<。.》>、/？?]";
            Pattern p = Pattern.compile(regEx);
            Matcher m = p.matcher(orgStr);
            return m.replaceAll("");
        }
        return null;
    }

    /**
     * 格式化打印json字符串
     * @param json
     */
    public static void prettyPrintJson(String json) {
        JSONObject object = JSONObject.parseObject(json);
        String pretty = JSON.toJSONString(object, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
        System.out.println(pretty);
    }

    /**
     * 格式化打印json对象
     * @param jsonObject
     */
    public static void prettyPrintJson(JSONObject jsonObject) {
        String pretty = JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
        System.out.println(pretty);
    }

    public static void main(String[] args) {

    }

}
